package tech.aistar.design.singleton;

import java.io.Serializable;

/**
 * 本类用来演示: 双重锁检测 - 为了解决懒汉模式在多线程场景下不安全
 *
 * @author: success
 * @date: 2022/7/22 3:45 下午
 */
public class Singleton04 implements Serializable {
    //2. 提供本类的唯一的实例作为它的静态属性
    //volatile - 禁止JVM的指令重排 - 优化

    //没有进行JVM指令重排
    //User user = new User();
    //①申请空间
    //②初始化对象 - 调用构造方法
    //③将对象的地址赋值给user

    //经过JVM的指令重排之后的顺序,实际上真正的顺序
    //①申请空间 - 地址已经出来了
    //②对象的地址赋值给user
    //③初始化对象 - 调用构造方法(消耗时间)

    private static volatile Singleton04 instance;

    //1. 私有化构造 - 为了不让外界去new
    private Singleton04(){
        //初始化的业务...
        System.out.println("构造方法...");
    }

    public static Singleton04 getInstance(){
        //防止后面的线程再去频繁竞争"锁"
        if(null==instance){//T1,T2 = > null
            synchronized (Singleton04.class){//T2在等待
                //只能由一个线程进入 - 同步代码块
                //T1进入了...
                if(null==instance){
                    //①申请空间 - 内存地址出来了
                    //②instance = 对象的内存地址 => instance已经不为null
                    //③慢慢调用构造,构造完毕之后,对象是完整的合法的对象.
                    instance = new Singleton04();
                    //T1虽然对instance赋值成功,但是此时instance指向的是一个不完整的对象
                    //慢悠悠过来的线程开始自行instance==null的判断,为false,其余线程直接拿到instance
                    //其余线程去使用了一个instance指向的那个不完整的对象 - 发生一些不可控的结果
                }
            }
        }
        return instance;
    }

    public void test(){
        System.out.println("-----");
    }
}
